/*!
 * Created by OJesusO on 2017/11/23.
 * @description BlockAction
 * @author OJesusO
 * @last 2017/12/14
 */
(function(root, name, factory) {
    if (typeof define === 'function' && define.amd) {
        //AMD
        define(['jquery'], function($){
            return factory(name, $);
        });
    } else if (typeof exports === 'object') {
        //Node, CommonJS之类的
        module.exports = factory(name, require('jquery'));
    } else {
        //浏览器全局变量(root 即 window)
        root[name] = factory(name, root.jQuery)[name];
    }
}(this, 'BlockAction', function(name, $) {
    //使用严格模式
    "use strict";

    /**
     * 默认配置
     */
    var CONF = {
        debug: 1,   //是否开启 debug
        stoped: 0,  //是否停止运行动画
        element: '',    //操作元素对象 或 可用于 jquery 方式获取的字符串
        moveStep: 10,   //移动步长, 10px
        angleStep: 1,   //旋转补偿, 1°
        minZoom: 0.1,   //最小缩放比例
        maxZoom: 4,     //最大缩放比例
        minZoomStep: 0.1,   //最小缩放步长
        maxZoomStep: 1,     //最大缩放步长
        direction: 0,       //默认操作元素的方向, 0:左 1:上 2:右 3:下
        defaultTimeout: 100,    //默认 timeout 时长
        images: [],     //可切换图片数组
    },
    tool = new(function() {
        this.getObjLength = function(obj) {
            if (typeof(obj) == 'object' && obj != null) {
                return Object.keys(obj).length;
            } else {
                return 0;
            }
        };
        this.getUnixTime = function(dateStr) {
            if (!dateStr) {
                var date = new Date().getTime();
            } else {
                var date = new Date(dateStr.replace(/-/g, '/')).getTime();
            }
            return (date.toString().substr(0, 10)) * 1;
        };
        this.isArray = function (param) {
			return type(param) === '[object Array]';
		};
        this.isObject = function (param) {
			return type(param) === '[object Object]';
		};
        this.isFunction = function (param) {
			return type(param) === '[object Function]';
		};
        this.isString = function (param) {
			return type(param) === '[object String]';
		};
        this.isBoolean = function (param) {
			return type(param) === '[object Boolean]';
		};
        this.isNumber = function (param) {
			return type(param) === '[object Number]';
		};
        this.isWindow = function(param) {
			return param != null && param === param.window;
		};
        this.isPlainObject = function(param) {
			return tool.isObject(param) && !tool.isWindow(param) && Object.getPrototypeOf(param) === Object.prototype;
		};

		function type (param) {
			return param == null ? String(param) : Object.prototype.toString.call(param)||'object';
		};
    }),
    console = window.console;

    /**
     * 继承方法
     */
    function Extend(Child, Parent, copy) {
        if (copy) {
            Child.prototype = new Parent();
            Child.prototype.constructor = Child;
            Child.uber = Parent.prototype;
        } else {
            var F = function() {};
            F.prototype = Parent.prototype;
            Child.prototype = new F();
            Child.prototype.constructor = Child;
            Child.uber = Parent.prototype;
        }
    };


    /**
     * BlockAction 主方法
     */
    function BlockAction(element, config) {
        var _OBJ = this,
        _status = {};

        _OBJ.CONF = {};     //配置对象
        _OBJ.Queue = {};    //队列对象
        _OBJ.Images = {};   //图片管理对象
        _OBJ.elementObj = {};   //元素对象

        _OBJ.Run = function () {
            //自动运行方法
            if (false === _OBJ.checkAndInitConf(element, config)) {
                console.error('Element is error!');
                return [false];
            }
            if (true === _OBJ.initObject()) {
                return _OBJ.elementObj.data('_BlockAction');
            }
            _OBJ.listenEven();
            if (_OBJ.elementObj.has('img')) {
                _OBJ.changeImage(null, null, 'auto', function(){
                    _status = _OBJ.markStatus();
                });
            } else {
                _status = _OBJ.markStatus();
                _OBJ.elementObj.data({
                    WH: {
                        w: _OBJ.elementObj.width(),
                        h: _OBJ.elementObj.height(),
                    },
                    zoom: 1,
                });
            }
            return this;
        };
        _OBJ.move = function (num, timeout, conf) {
            //移动方法, num:步数, timeout:该时间后执行, conf:额外配置
            num = num || 1;
            var moveStep = _OBJ.getConfig('moveStep', 1);
            _OBJ.Queue.push(function(sec){
                console.log(`moving: 于 ${sec}s 后执行的该操作(移动 ${num} 步);`);
                _OBJ.calcMove(num, moveStep, conf);
            }, timeout);
        };
        _OBJ.wait = function (timeout) {
            //延时方法, timeout:该时间后执行
            var moveStep = 0;
            _OBJ.Queue.push(function(sec){
                console.log(`wait: 于 ${sec}s 后执行的该操作);`);
            }, timeout);
        };
        _OBJ.moveTo = function (x, y, timeout, type) {
            //移动到指定的坐标, x:X轴|left值, y:Y轴|top值, timeout:该时间后执行, type:定位点类型
            _OBJ.Queue.push(function(sec){
                console.log(`moving to: 于 ${sec}s 后执行的该操作(移动到 x:${x}, y:${y});`);
                switch (type) {
                    case 1: case 'nw': case 'wn':
                        //左上角定位
                        break;
                    case 2: case 'n':
                        //上中心定位
                        x = x + _OBJ.elementObj.width() / 2;
                        break;
                    case 3: case 'en': case 'ne':
                        //右上角定位
                        x = x + _OBJ.elementObj.width();
                        break;
                    case 4: case 'e':
                        //右中心定位
                        x = x + _OBJ.elementObj.width();
                        y = y + _OBJ.elementObj.height() / 2;
                        break;
                    case 5: case 'se': case 'es':
                        //右下角定位
                        x = x + _OBJ.elementObj.width();
                        y = y + _OBJ.elementObj.height();
                        break;
                    case 6: case 's':
                        //下中心定位
                        x = x + _OBJ.elementObj.width() / 2;
                        y = y + _OBJ.elementObj.height();
                        break;
                    case 7: case 'ws': case 'sw':
                        //左下角定位
                        y = y + _OBJ.elementObj.height();
                        break;
                    case 8: case 'w':
                        //左中心定位
                        y = y + _OBJ.elementObj.height() / 2;
                        break;
                    case 0: case 'c':
                        //正中心定位
                        x = x + _OBJ.elementObj.width() / 2;
                        y = y + _OBJ.elementObj.height() / 2;
                        break;
                    default:
                        //左上角定位
                }
                _OBJ.elementObj.css({
                    top: y + 'px',
                    left: x + 'px',
                });
            }, timeout);
        };
        _OBJ.rotate = function (num, timeout, conf) {
            //旋转方法, num:步数, timeout:该时间后执行, conf:额外配置
            num = num || 1;
            var angleStep = _OBJ.getConfig('angleStep', 1);
            _OBJ.formatRotate();
            _OBJ.Queue.push(function(sec){
                console.log(`rotating: 于 ${sec}s 后执行的该操作(旋转 ${num} 次);`);
                _OBJ.calcRotate(num, angleStep, conf);
            }, timeout);
        };
        _OBJ.rotateTo = function (r, timeout) {
            //旋转到指定的角度, r:角度值, timeout:该时间后执行
            _OBJ.Queue.push(function(sec){
                console.log(`rotating to: 于 ${sec}s 后执行的该操作(旋转到 ${r}°);`);
                _OBJ.setRotate(r);
            }, timeout);
        }
        // _OBJ.flip = function (direction, timeout) {
        //     //翻转方法, direction:方向(0:垂直,1:水平), timeout:该时间后执行
        //     _OBJ.Queue.push(function(){
        //         console.log(`directioning: 于 ${sec}s 后执行的该操作(翻转 ${num} 次);`);
        //     }, timeout);
        // };
        _OBJ.zoom = function (zoom, timeout) {
            //变焦方法, zoom:倍率, timeout:该时间后执行
            _OBJ.Queue.push(function(sec){
                console.log(`zooming: 于 ${sec}s 后执行的该操作(倍率变为 ${zoom});`);
                _OBJ.calcZoom(zoom);
            }, timeout);
        };
        _OBJ.changeImage = function (url, width, height, after) {
            //换图方法, url:图片地址, width:宽度, height:高度, after:执行后回调
            var img = _OBJ.elementObj.find('img');
            if (url) {
                if (url === img.attr('src')) {
                    return true;
                }
                var obj = _OBJ.Images.get(url);
                _OBJ.elementObj.append(obj);
                img.remove();
                img = obj;
            }

            width = width || _OBJ.elementObj.width();
            height = height || _OBJ.elementObj.height();
            _OBJ.noAnimationSet(function(){
                _OBJ.elementObj.css({
                    width: width,
                });
                if (height === 'auto') {
                    height = img.height();
                }
                _OBJ.elementObj.css({
                    height: height,
                });
                _OBJ.elementObj.data({
                    WH: {w: width, h: height},
                    zoom: 1,
                });
            }, after);
        };
        _OBJ.reset = function () {
            //重置动画操作
            _OBJ.Queue.clearAll();
            _OBJ.resetStatus(_status);
        };
        _OBJ.stop = function () {
            //停止动画操作
            _OBJ.Queue.stop();
        };
        _OBJ.start = function (action) {
            //开始动画操作, action:立即执行
            _OBJ.Queue.start(action);
        };
        _OBJ.isAction = function () {
            //是否正在执行操作中
            return (!_OBJ.Queue.isStop()) && _OBJ.Queue.hasItem();
        };
        _OBJ.getInfo = function () {
            var pos = this.elementObj.position();
            return {
                x: pos.left,
                y: pos.top,
                r: this.getRotate(),
            };
        };

        return _OBJ.Run();
    };
    Extend(BlockAction, function _BlockAction() {
        var rotate_reg = new RegExp('rotate\\(([-\\d]+)deg\\)');
        this.noAnimationSet = function (callback, after) {
            //没有动画方式设置
            var tmp = this.elementObj.css('transition');
            this.elementObj.css('transition', 'none');
            if (tool.isFunction(callback)) {
                callback();
            }
            setTimeout(function(){
                this.elementObj.css('transition', tmp);
                if (tool.isFunction(after)) {
                    after();
                }
            }.bind(this));
        };
        this.formatRotate = function () {
            //格式化角度
            var transform = this.elementObj.get(0).style.transform;
            if (rotate_reg.test(transform)) {
                var rotate = getRotate(this.elementObj);
                if (rotate < 0) {
                    rotate += Math.ceil(Math.abs(rotate) / 360) * 360;
                } else if (rotate > 360) {
                    rotate = rotate % 360;
                } else {
                    return true;
                }
                this.noAnimationSet(function(){
                    this.setRotate(rotate);
                }.bind(this));
            }
        };
        this.calcRotate = function (num, angleStep, conf) {
            //计算角度
            conf = conf || {};
            var rotate = num * angleStep,
            transform = this.elementObj.get(0).style.transform;

            if (rotate_reg.test(transform)) {
                rotate += getRotate(this.elementObj);
            }
            this.setRotate(rotate);
        };
        this.calcMove = function (num, step, conf) {
            //计算移动
            conf = conf || {};
            var tmp = getMoveLength(this.elementObj, num * step),
            top = tmp[1], left = tmp[0];

            // tmp = this.elementObj.position();
            this.elementObj.css({
                top: top + Number(this.elementObj.get(0).offsetTop) + 'px',
                left: left + Number(this.elementObj.get(0).offsetLeft) + 'px',
            });
        };
        this.calcZoom = function (zoom) {
            //计算倍率 - 不使用 css 的 zoom, zoom 会 导致定位和旋转问题, 这里采用自己实现
            var old = Number(this.elementObj.data('zoom'));
            if (zoom === true) {
                zoom = old + this.getConfig('maxZoomStep');
            } else if (zoom === false) {
                zoom = old - this.getConfig('maxZoomStep');
            } else if (zoom === null) {
                zoom = 1;
            } else if (zoom === 'in') {
                zoom = old + this.getConfig('minZoomStep');
            } else if (zoom === 'out') {
                zoom = old - this.getConfig('minZoomStep');
            } else if (tool.isNumber(zoom) || tool.isString(zoom)) {
                zoom = zoom * 1;
            } else {
                return false;
            }
            var wh = this.elementObj.data('WH'),
            min = this.getConfig('minZoom'),
            max = this.getConfig('maxZoom');
            if (zoom < 0 ||
                zoom < min) {
                zoom = min;
            } else if (zoom > max) {
                zoom = max;
            }
            this.elementObj.width(wh.w * zoom);
            this.elementObj.height(wh.h * zoom);
            this.elementObj.data('zoom', zoom);
        };
        this.setRotate = function (rotate, has) {
            var transform = this.elementObj.get(0).style.transform;

            if (rotate_reg.test(transform) || has) {
                transform = transform.replace(rotate_reg, 'rotate('+ rotate +'deg)');
            } else {
                transform = transform.trim() + ' rotate('+ rotate +'deg)';
            }

            this.elementObj.css({
                transform: transform,
            });
        };
        this.getRotate = function () {
            this.formatRotate();
            return getRotate(this.elementObj);
        };
        this.markStatus = function () {
            //标记状态
            return {
                image: this.elementObj.find('img'),
                style: this.elementObj.attr('style') || '',
            };
        };
        this.resetStatus = function (_status) {
            //重设状态
            this.elementObj.attr('style', _status.style);
            if (!this.elementObj.find('img').is(_status.image)) {
                this.elementObj.find('img').remove();
                this.elementObj.append(_status.image);
            }
            setTimeout(function(){
                this.elementObj.data({
                    WH: {
                        w: this.elementObj.width(),
                        h: this.elementObj.height(),
                    },
                    zoom: 1,
                });
            }.bind(this), 500);
        };
        this.checkAndInitConf = function (element, config) {
            //检查并初始化配置
            if (!element && (!config || !config.element)) {
                return false;
            } else if (tool.isPlainObject(element)) {
                if (!element.element) {
                    return false;
                }
                this.initConf(CONF, element);
            } else if (tool.isPlainObject(config)) {
                if (element && !config.element) {
                    config.element = element;
                }
                this.initConf(CONF, config);
            } else {
                config = {
                    element: element
                };
                this.initConf(CONF, config);
            }
            return true;
        };
        this.listenEven = function() {
            //监听事件
        };
        this.initConf = function(CONF, conf) {
            //初始化配置
            this.CONF = $.extend(true, {}, CONF, conf);
            if (!this.getConfig('debug')) {
                console.log = function() {};
            }
        };
        this.initObject = function() {
            //初始化对象
            this.elementObj = $(this.getConfig('element'));
            var tmp = this.elementObj.data('_BlockAction');
            if (tmp && tmp.elementObj.is(this.elementObj)) {
                return true;
            } else {
                this.elementObj.data('_BlockAction', this);
            }
            this.Images = new BlockImages(this);
            this.Queue = new BlockQueue(this);
        };
        this.getConfig = function(key, dft) {
            //获取配置
            var keys = $.isArray(key) ? key : key.split('.');
            if (tool.getObjLength(keys) > 1) {
                key = keys.pop();
                var data = this.getConfig(keys, dft);
                if (!data || typeof(data[key]) === 'undefined' || data[key] === null) {
                    data = this.getConfig(keys, true);
                    if (!data || typeof(data[key]) === 'undefined' || data[key] === null) {
                        return null;
                    }
                }
                return data[key];
            } else {
                var conf = dft === true ? CONF : this.CONF;
                if (typeof(conf[key]) === 'undefined' || conf[key] === null) {
                    return dft === true ? null : this.getConfig(key, true);
                } else {
                    return conf[key];
                }
            }
        };

        function getMoveLength (elementObj, length) {
            //获取移动长度返回[x, y]
            if (!length) {
                return [0, 0];
            }
            var rotate = getRotate(elementObj), tmp = null;
            if (rotate < 0) {
                rotate += Math.ceil(Math.abs(rotate) / 360) * 360;
            } else if (rotate > 360) {
                rotate = rotate % 360;
            }
            if (rotate == 0) {
                return [-1 * length, 0];
            } else if (rotate == 90) {
                return [0, -1 * length];
            } else if (rotate == 180) {
                return [1 * length, 0];
            } else if (rotate == 270) {
                return [0, 1 * length];
            } else if (rotate == 360) {
                return [-1 * length, 0];
            } else if (rotate > 0 && rotate < 90) {
                tmp = getXY(length, rotate);
                return [-1 * tmp[0], -1 * tmp[1]];
            } else if (rotate > 90 && rotate < 180) {
                tmp = getXY(length, 180 - rotate);
                return [1 * tmp[0], -1 * tmp[1]];
            } else if (rotate > 180 && rotate < 270) {
                tmp = getXY(length, rotate - 180);
                return [1 * tmp[0], 1 * tmp[1]];
            } else if (rotate > 270 && rotate < 360) {
                tmp = getXY(length, 360 - rotate);
                return [-1 * tmp[0], 1 * tmp[1]];
            }
        };
        function getXY (length, rotate) {
            //根据 长度|斜边 和角度获取 其它两边，确保对边为 y, 临边为 x
            var x = Math.abs(Math.cos(rotate) * length),
                y = Math.abs(Math.sin(rotate) * length);
            if (length < 0) {
                return [-x, -y]
            } else {
                return [x, y];
            }
        };
        function getRotate (elementObj) {
            //获取对象旋转角度
            // var transform = elementObj.css('transform');
            var transform = elementObj.get(0).style.transform;
            if (transform) {
                var rotate = transform.match(rotate_reg);
                return rotate && rotate[1] ? Number(rotate[1]) : 0;
                // return eval('get' + transform);
            }
            return 0;
        };

        /*
         * 解析matrix矩阵，0°-360°，返回旋转角度
         * 当a=b||-a=b,0<=deg<=180
         * 当-a+b=180,180<=deg<=270
         * 当a+b=180,270<=deg<=360
         *
         * 当0<=deg<=180,deg=d;
         * 当180<deg<=270,deg=180+c;
         * 当270<deg<=360,deg=360-(c||d);
         * */
        function getmatrix(a, b, c, d, e, f) {
            var aa = Math.round(180 * Math.asin(a) / Math.PI);
            var bb = Math.round(180 * Math.acos(b) / Math.PI);
            var cc = Math.round(180 * Math.asin(c) / Math.PI);
            var dd = Math.round(180 * Math.acos(d) / Math.PI);
            var deg = 0;
            if (aa == bb || -aa == bb) {
                deg = dd;
            } else if (-aa + bb == 180) {
                deg = 180 + cc;
            } else if (aa + bb == 180) {
                deg = 360 - cc || 360 - dd;
            }
            return deg >= 360 ? 0 : deg;
            //return (aa+','+bb+','+cc+','+dd);
        }
    }, true);


    function BlockImages(_OBJ) {
        var _obj = this,
        _images = {};

        _obj.set = function (images) {
            setTimeout(function(){
                if (tool.isArray(images)) {
                    $.each(images, function(){
                        add(this);
                    });
                } else if (tool.isString(images)) {
                    add(images);
                }
            });
        };
        _obj.get = function (key) {
            return _images[key] || false;
        };

        function add (src) {
            if (_images[src]) {
                return true;
            }
            _images[src] = $(new Image());
            _images[src].attr('src', src);
            _images[src]._src = src;
        };

        _obj.set(_OBJ.getConfig('images', []));
    };


    function BlockQueue(_OBJ) {
        var _obj = this,
        _stop = false,
        _action = false,
        _queue = [],
        nowAction = null;

        _obj.stop = function () {
            //设置暂停操作
            _stop = true;
        };
        _obj.start = function (action) {
            //设置开始操作
            _stop = false;
            if (action) {
                _obj.next();
            }
        };
        _obj.push = function (callback, timeout) {
            //压进队列
            var time = formatTime(timeout);
            _queue.push({
                callback: function(){
                    nowAction = setTimeout(function(){
                        callback(time/1000);
                        _action = false;
                        _obj.next();
                    }, time);
                },
            });
            _obj.next();
        };
        _obj.next = function () {
            //执行下一队列方法
            if (_action) {
                return false;
            } else {
                _action = true;
            }
            if (_stop) {
                _action = false;
                return true;
            } else if (!_obj.hasItem()) {
                _action = false;
                return false;
            }
            var action = _queue.shift();
            action.callback();
        };
        _obj.clearAll = function () {
            //清除所有
            _queue = [];
            if (_OBJ.getConfig('stoped')) {
                _obj.stop();
            } else {
                _obj.start();
            }
        };
        _obj.isStop = function () {
            return _stop;
        };
        _obj.hasItem = function () {
            return tool.getObjLength(_queue) > 0;
        };

        function formatTime (time) {
            //格式化时间
            if (tool.isNumber(time) || tool.isString(time)) {
                return time;
            } else if (tool.isArray(time) && time[1] == 's') {
                return time[0] * 1000;
            } else {
                return _OBJ.getConfig('defaultTimeout', 0);
            }
        };

        if (_OBJ.getConfig('stoped')) {
            _obj.stop();
        }
    };


    //暴露公共方法
    var _exports = {};
    _exports[name] = BlockAction;
    return _exports;
}));
